import { expect } from '@jest/globals';
import * as compressing from 'compressing';
import fs from 'fs-extra';
import fse from 'fs-extra';
import fsExtra from 'fs-extra';
import JSON5 from 'json5';
import path from 'path';

import { initExecuteCommand, runHvigorAsync } from '../../common/common';
import {
  AbilityType,
  APIType,
  APIVersion,
  CaseLevel,
  IsEnable,
  LanguageType,
  ModuleTemplateType,
  RuntimeOSType,
  SDKType,
  SignType
} from '../../plugins/project-builder/models/constants';
import { Project } from '../../plugins/project-builder/models/project-models';
import { ICaseRecord } from '../../plugins/report-builder/report-models';
import { TestCaseBuilder } from '../../plugins/task-builder/task-case-builder';
import { ProjectBuildOption, TestCaseFun } from '../../plugins/task-builder/test-case';
import { TestTaskOption } from '../../plugins/task-builder/test-task-option';

const projectBuilderOption: ProjectBuildOption = {
  template: {
    sdk: SDKType.Single,
    runtimeOS: RuntimeOSType.HarmonyOS,
    apiVersion: APIVersion.API10,
    apiType: APIType.STAGE,
    language: LanguageType.ArkTs,
    abilityType: AbilityType.Application,
    entryTemplateType: ModuleTemplateType.EmptyAbility
  },
};
const taskConfig: TestTaskOption = {
  caseLevel: CaseLevel.L1,
  sign: SignType.NoSign,
  ohpmInstall: IsEnable.DisAble,
};

async function updateConfig(project: Project) {
  const projectRoot = project.projectRootPath();
  const dataRoot = await fs.readFile(path.resolve(projectRoot, 'build-profile.json5'));
  const entryPath = await fs.readFile(path.resolve(project.getModule('entry').moduleRootPath(), 'build-profile.json5'));

  // 解析JSON5文件
  const objRoot = JSON5.parse(dataRoot.toString());
  const entryObj = JSON5.parse(entryPath.toString());

  objRoot.app.buildModeSet = [
    {
      'name': 'custom',
      'buildOption': {
        'debuggable': true
      }
    }
  ];

  entryObj.buildOptionSet = [
    {
      'name': 'default',
    },
    {
      'name': 'debug',
    },
    {
      'name': 'release',
    },
    {
      'name': 'option',
    }
  ];

  entryObj.buildModeBinder = [
    {
      'buildModeName': 'custom',
      'mappings': [
        {
          'targetName': 'default',
          'buildOptionName': 'option'
        }
      ]
    }
  ];

  // 将对象转换回JSON5字符串
  const jsonToStr = JSON.stringify(objRoot);

  const jsonEntryStr = JSON.stringify(entryObj);

  // 将修改后的字符串写回文件
  await fs.writeFile(
    path.resolve(projectRoot, 'build-profile.json5'), jsonToStr, 'utf8');

  await fs.writeFile(
    path.resolve(project.getModule('entry').moduleRootPath(), 'build-profile.json5'), jsonEntryStr, 'utf8');

}

/**
 * 清理构建产物
 *
 * @param {Project} project
 * @return {Promise<void>}
 */
async function cleanTarget(project: Project) {
  const commandClean = initExecuteCommand({
    mode: 'module',
    product: 'default',
    tasks: 'clean'
  });
  await runHvigorAsync(project.projectRootPath(), commandClean);
}


// 1. 选择执行Build Hap，entry模块下会生成hap包，且hap包里面有.abc文件和.map文件
async function buildMakeDefault(project: Project, record: ICaseRecord) {
  const commands = initExecuteCommand({
    mode: 'module',
    product: 'default',
    tasks: 'assembleHap',
    buildMode: 'custom'
  });
  const result = await runHvigorAsync(project.projectRootPath(), commands);
  record.addStep('选择Build Hap构建', result);
  expect(result.stdout).toContain('BUILD SUCCESSFUL');

  // 判断输出文件有且仅有一个entry-default-hap包 且hap包里面有.abc文件和.map文件
  const outputs = path.resolve(project.getModule('entry').moduleRootPath(), 'build', 'default', 'outputs');
  const outputsExists = await fse.pathExists(outputs);
  expect(outputsExists).toBe(true);
  const outputsDirs: string[] = await fse.readdir(outputs);
  expect(outputsDirs.length).toEqual(1);
  const hapExists = await fse.pathExists(path.resolve(outputs, 'default', 'entry-default-unsigned.hap'));

  // 判断intermediates - loader_out下有.abc文件和.map文件
  const outputLoader = path.resolve(project.getModule('entry').moduleRootPath(), 'build/default/intermediates/loader_out');
  const abcExists = await fse.pathExists(path.resolve(outputLoader, 'default', 'ets', 'modules.abc'));
  const mapExists = await fse.pathExists(path.resolve(outputLoader, 'default', 'ets', 'sourceMaps.map'));

  expect(hapExists).toBe(true);
  expect(abcExists).toBe(true);
  expect(mapExists).toBe(true);
}

// 2.选择执行Build App，工程级目录下是否存在app包
async function buildAppDefault(project: Project, record: ICaseRecord) {
  const commands = initExecuteCommand({
    mode: 'project',
    product: 'default',
    tasks: 'assembleApp',
    buildMode: 'custom'
  });
  const result = await runHvigorAsync(project.projectRootPath(), commands);
  record.addStep('执行Build App编译构建', result);
  expect(result.stdout).toContain('BUILD SUCCESSFUL');

  const appExists = await fse.pathExists(
    path.resolve(project.projectRootPath(), 'build/outputs/default/myapplication-default-unsigned.app'));
  expect(appExists).toBe(true);

  // 解析app包的内容
  await fsExtra.copyFile(path.resolve(project.projectRootPath(), 'build/outputs/default/myapplication-default-unsigned.app'),
    path.resolve(project.projectRootPath(), 'build/outputs/default/myapplication-default-unsigned.zip'));
  await compressing.zip.uncompress(
    path.resolve(project.projectRootPath(), 'build/outputs/default/myapplication-default-unsigned.zip'),
    path.resolve(project.projectRootPath(), 'build/outputs/default/myapplication-default-unsigned'));

  // 查看app包里是否有hap包
  const applicationHapExist = await fsExtra.pathExists(
    // eslint-disable-next-line max-len
    path.resolve(project.projectRootPath(), 'build/outputs/default/myapplication-default-unsigned/entry-default.hap'));

  expect(applicationHapExist).toBe(true);

  // 解析hap包的内容
  await fsExtra.copyFile(path.resolve(project.projectRootPath(), 'build/outputs/default/myapplication-default-unsigned/entry-default.hap'),
    path.resolve(project.projectRootPath(), 'build/outputs/default/myapplication-default-unsigned/entry-default.zip'));
  await compressing.zip.uncompress(
    path.resolve(project.projectRootPath(), 'build/outputs/default/myapplication-default-unsigned/entry-default.zip'),
    path.resolve(project.projectRootPath(), 'build/outputs/default/myapplication-default-unsigned/entry-default'));

  // 查看hap包是否有.abc文件和.map文件
  const abcExists = await fse.pathExists(
    path.resolve(project.projectRootPath(), 'build/outputs/default/myapplication-default-unsigned/entry-default/ets/modules.abc'));
  const mapExists = await fse.pathExists(
    path.resolve(project.projectRootPath(), 'build/outputs/default/myapplication-default-unsigned/entry-default/ets/sourceMaps.map'));
  expect(abcExists).toBe(true);
  expect(mapExists).toBe(true);
}


const testFun: TestCaseFun = async (project, taskConfig, record) => {
  const projectRoot = project.projectRootPath();

  // 修改配置文件
  await updateConfig(project);

  // 1. 选择执行Build Hap，entry模块下会生成hap包，且hap包里面有.abc文件和.map文件
  await buildMakeDefault(project, record);
  await cleanTarget(project);

  // 2. 选择执行Build App，工程级目录下是否存在app包
  await buildAppDefault(project, record);
  await cleanTarget(project);

};

TestCaseBuilder.builder()
  .caseName('OPEN_LAB_AIDE_ZOS_GUI_BUILD_API10_FA_001')
  .description('01_工程级build-profile.json5新增buildMode配置项')
  .projectBuilderOption(projectBuilderOption)
  .taskConfig(taskConfig)
  .testFun(testFun)
  .load();
